#include "ntddk.h"
#include "stdio.h"
#include "stdlib.h"

#define word  unsigned short
#define dword unsigned int
#define byte  unsigned char
#pragma pack(1)
                                        
struct TABLE_INFO
{
    word  size;
    dword base;
} gdt, ldt;

                                       
struct Descriptor
{
     word limit_l;
     word base_l;
     byte base_m;
     byte access;
     byte limit_h;
     byte base_h;
}* gdtdesc;


char buf[100];
int gtype = 1;
int number = -1;

NTSTATUS driverInit  (IN PDEVICE_OBJECT dev, IN PIRP irp);
NTSTATUS driverControl (IN PDEVICE_OBJECT dev, IN PIRP irp);
VOID     driverUnload  (IN PDRIVER_OBJECT dev);
NTSTATUS write(IN PDEVICE_OBJECT dev, IN PIRP irp);
NTSTATUS read(IN PDEVICE_OBJECT dev, IN PIRP irp);

NTSTATUS complete(int size, IN PIRP irp)
{        
        irp->IoStatus.Status      = STATUS_SUCCESS;
        irp->IoStatus.Information = size;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
                 
        return STATUS_SUCCESS;
}
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject,IN PUNICODE_STRING RegistryPath)
{
        NTSTATUS       status;
        PDEVICE_OBJECT dev;
        UNICODE_STRING name;
        UNICODE_STRING link;
  
        driverObject->DriverUnload                         = driverUnload;
        driverObject->MajorFunction[IRP_MJ_CREATE]         = driverInit;
        driverObject->MajorFunction[IRP_MJ_CLOSE]          = driverInit;
        driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driverInit;
        driverObject->MajorFunction[IRP_MJ_READ] = read;
        driverObject->MajorFunction[IRP_MJ_WRITE] = write;
  
        RtlInitUnicodeString(&name,L"\\Device\\driver");
  
        status = IoCreateDevice(driverObject,sizeof(PDEVICE_OBJECT),&name,FILE_DEVICE_UNKNOWN,0,FALSE,&dev);
        dev->Flags |= DO_BUFFERED_IO;
        if(!NT_SUCCESS(status))return status;
        RtlInitUnicodeString(&link,L"\\??\\driver");
  
        return IoCreateSymbolicLink(&link,&name);
}
  
NTSTATUS driverInit(IN PDEVICE_OBJECT dev, IN PIRP irp)
{
        return complete(0, irp);
}
  
VOID driverUnload(IN PDRIVER_OBJECT dev)
{
        UNICODE_STRING deviceLink;
        RtlInitUnicodeString(&deviceLink,L"\\??\\driver");
        IoDeleteSymbolicLink(&deviceLink);
        IoDeleteDevice(dev->DeviceObject);
}

NTSTATUS write(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
        void* buffer = NULL;
        long size = 0;
        word a = 0;
  
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
  
        size  = stack->Parameters.Write.Length;
        buffer = irp->AssociatedIrp.SystemBuffer;
        if (((char*)buffer)[0] == 'g')
        {
                number = -1;
                gtype = 1;
                __asm sgdt [gdt];
        }
        else if (((char*)buffer)[0] == 'l')
        {
                number = -1;
                gtype = 0;
                __asm sldt [gdt];
        }
        else
        {
            number = atoi(((char*)buffer));
            if(gdt.size <= number)
            {
                  number = -1;      
            }
        }       
     
    if(number != -1)  
    {
     gdtdesc =(struct Descriptor*)(gdt.base + ((dword)0x08*number)); 
     memcpy(buf, (gdtdesc), sizeof(struct Descriptor)); 
    }   
    else
    memcpy(buf, &gdt, sizeof(struct TABLE_INFO));
         
         
#if DBG
       if (number == -1)
       {
          DbgPrint("Size %d", size);
          DbgPrint("Buffer: %s",buf);
          DbgPrint("Gdt base 0x%8x", gdt.base);
          DbgPrint("Gdt size %d", gdt.size); 
       } else {
          DbgPrint("Limit 0:15 %d, Limit 48:55 %d\n, Base 16:31 %d, Base 32:39 %d\n, Base 56:63 %d, Access %d\n",
          ((struct Descriptor*)buf)->limit_l, ((struct Descriptor*)buf)->limit_h, gdtdesc->base_l, gdtdesc->base_m,
          gdtdesc->base_h, gdtdesc->access);
       }
#endif
  
        return complete(size, irp);
}
NTSTATUS read(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
        void* buffer = NULL;
        long size = 0;
  
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
  
        size  = stack->Parameters.Read.Length;
        buffer = irp->AssociatedIrp.SystemBuffer;
  
        RtlCopyMemory(buffer,&buf,size);
#if DBG
        DbgPrint(gtype);
#endif
                 
        return complete(size, irp);
}
